﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SongSharp.Domain.Objects;
using SongSharp.Logging;

namespace SongSharp.Domain.Suggesting.VaryVogueValue
{
    public class VistaGenerator : ChanceGenerator
    {
        public static readonly double[] HeatPlayedHours = new double[] { 1, 2, 4, 8, 16, 32 };
        public static readonly double[] HeatSkippedHours = new double[] { 16, 32, 64, 128, 256, 512 };
        public static readonly double[] HeatAddedDays = new double[] { 60, 40, 20, 9, 6, 3 };
                
        static VistaGenerator()
        {
            RulesTable.Add("vista_heat_played_hours", new RuleSet(HeatPlayedHours, 0.5));
            RulesTable.Add("vista_heat_skipped_hours", new RuleSet(HeatSkippedHours, 0.5));
            RulesTable.Add("vista_heat_added_days", new RuleSet(HeatAddedDays, 0.7));
        }

        public override ChanceValue Generate(Track track)
        {
            // Generate heat values according to the tracks statistics
            ChanceValue heatPlayed = GenerateHeat(track, TrackHandlingType.PlayedTrackToEnd);
            ChanceValue heatSkipped = GenerateHeat(track, TrackHandlingType.SkippedTrack);
            ChanceValue heatAdded = GenerateHeat(track, TrackHandlingType.AddedTrack);

            //// Scale all heat values and change their values by reference
            ////ChanceValue[] scaled = new ChanceValue[] { heatPlayed, heatSkipped, heatAdded };
            ////RulesManager.Helper.Scale(ref scaled);

            ChanceValue v = heatPlayed + heatSkipped;

            Logger.Log("   Addition of [" + Math.Round(heatPlayed.Value, 4) + ";" + heatPlayed.DegreeOfBelief
                + "] + [" + Math.Round(heatSkipped.Value, 4) + ";" + heatSkipped.DegreeOfBelief + "] = ["
                + Math.Round(v.Value, 4) + "]");

            ChanceValue w = v + heatAdded;

            Logger.Log("   Addition of [" + Math.Round(v.Value, 4) + ";" + v.DegreeOfBelief
                + "] + [" + Math.Round(heatAdded.Value, 4) + ";" + heatAdded.DegreeOfBelief + "] = ["
                + Math.Round(w.Value, 4) + "]");

            return w;
        }

        /// <summary>
        /// Generates a chance value according to the elapsed time between now and the last time the track performed an
        /// evnrionment capture of the type TrackHandlingType.
        /// The longer the elapsed time the better the chance value will become. 
        /// If there is no last date available the generated value will be the best value.
        /// This function depends on the ruleset arrays.
        /// </summary>
        /// <param name="track">The track with its embedded statistic object</param>
        /// <param name="handling">Defines the type of the last environment capture object</param>
        /// <returns>An object of type ChanceValue</returns>
        private ChanceValue GenerateHeat(Track track, TrackHandlingType handling)
        {
            ChanceValue chance = ChanceValue.MAX;
            TimeSpan span = TimeSpan.MaxValue;

            switch (handling)
            {
                case TrackHandlingType.AddedTrack:
                    span = DateTime.Now - (DateTime)track.Statistic.DateAdded;
                    chance = RulesManager.CreateInterpretation("vista_heat_added_days", span.TotalDays);
                    chance.ValueType = ChanceValue.VVVType.Vista_Heat_Added_Days;

                    // Logging/Debugging - Start
                    Logger.Log("   Vista, added-heat-value: " + Math.Round(span.TotalDays) + " d, x = "
                        + Math.Round(chance.Value, 4) + ", DeB = " + chance.DegreeOfBelief);
                    // Logging/Debugging - End
                    break;
                case TrackHandlingType.PlayedTrackToEnd:
                    chance.ValueType = ChanceValue.VVVType.Vista_Heat_Played_Hours;
                    chance.DegreeOfBelief = 1;
                    break;
                case TrackHandlingType.SkippedTrack:
                    chance.ValueType = ChanceValue.VVVType.Vista_Heat_Skipped_Hours;
                    chance.DegreeOfBelief = 1;
                    break;
            }

            if (handling != TrackHandlingType.AddedTrack)
            {
                EnvironmentCapture lastCapture = track.Statistic.GetLastAction(handling);

                if (lastCapture != null)
                {
                    span = DateTime.Now - (DateTime)lastCapture.Date;
                    switch (handling)
                    {
                        case TrackHandlingType.PlayedTrackToEnd:
                            chance = RulesManager.CreateInterpretation("vista_heat_played_hours", span.TotalHours);
                            chance.ValueType = ChanceValue.VVVType.Vista_Heat_Played_Hours;

                            // Logging/Debugging - Start
                            Logger.Log("   Vista, played-heat-value: " + Math.Round(span.TotalHours) + " h, x = "
                                + Math.Round(chance.Value, 4) + ", DeB = " + chance.DegreeOfBelief);
                            // Logging/Debugging - End

                            break;
                        case TrackHandlingType.SkippedTrack:
                            chance = RulesManager.CreateInterpretation("vista_heat_skipped_hours", span.TotalHours);
                            chance.ValueType = ChanceValue.VVVType.Vista_Heat_Skipped_Hours;

                            // Logging/Debugging - Start
                            Logger.Log("   Vista, skipped-heat-value: " + Math.Round(span.TotalHours) + " h, x = "
                                + Math.Round(chance.Value, 4) + ", DeB = " + chance.DegreeOfBelief);
                            // Logging/Debugging - End

                            break;
                    }
                }
            }
            return chance;
        }
    }
}
